/**
 * @file main.c
 * @brief
 * @author h0rr0rr_drag0n <h0rr0rr_drag0n@vindekapets.ru
 * @date 01 July 2010 20:28:56
 *
 * Slider (eg brightness, volume) for tiling WM
 */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/select.h>
#include "web-addresses.h"
#include "define.h"

/**
 * @brief Non-zero if SIGCHLD come
 */
volatile int child_flag = 0;
/**
 * @brief Non-zero if SIGINT or SIGQUIT come
 */
volatile int abort_flag = 0;

/**
 * @brief Print help message
 *
 * This function print help message about program
 * usage.
 */
void echo_help() {
    printf("Usage: osd_server [KEY]\n");
    printf("Keys are:\n");
    printf(" --no-daemon\trun not in daemon mode\n");
    printf(" --help\t\tshow help\n");
    printf("\n");
    printf("Home page: %s\n", HOME_PAGE);
    printf("About bugs mail to: %s\n", EMAIL);

    return;
}

/**
 * @brief Function for parsing cmd args
 *
 * Fucntion parse given cmd arguments and return
 * we proper value. Returns:
 *   -1 or -2 in error
 *   1 if we might run as no daemon
 *   2 if we should print help message
 */
int parse_argv(int argc, char * argv[]) {
    if (argc == 2) {
        if (strncmp("--no-daemon", argv[1], 11) == 0) {
            return 1;
        } else if (strncmp("--help", argv[1], 6) == 0) {
            return 2;
        } else {
            return -2;
        }
    } else if (argc > 2) {
        fprintf (stderr, "Only one command-line argument!\n");
        return -1;
    }

    return 0;
}

/**
 * @brief  Main program cycle is in this function
 *
 * We check in infinite cycle for program abort and SIGCHILD handle 
 * flags and check for new data in pipe with select().
 */
int main(int argc, char * argv[]) {
    int daemonize = 1; /* run as daemon by default */
    int readfd = 0; /* FIFO fd */
    fd_set rset;
    struct timeval timeout;
    int select_retval = 0;
    char cmd_str[STRLEN] = "\0";
    int cmd_pointer = 0;
    int getchar_retval = 0;

    switch (parse_argv(argc, argv)) {
        case -2:
        case -1:
            return -1;
        case 1:
            daemonize = 0;
            break;
        case 2:
            echo_help();
            return 0;
            break;
        case 0:
            break;
        default:
            fprintf(stderr, "Error: parse_argv() return strange value!\n");
            return -2;
    } /* switch() */

    if (osd_slider_init(daemonize)) {
        emerg_exit();
    }

    if ((readfd = pipe_open(FIFO_PATH)) < 0) {
        emerg_exit();
    }

    FD_ZERO(&rset);

    while (1) {
        if (check_sigabrt()) {
            emerg_exit();
        }
        if (check_sigchld()) {
            emerg_exit();
        }

        FD_SET(readfd, &rset);
        /* we need reinitialize struct timeval for select()
         * in Linux every time :-( */
        if (memset(&timeout, 0, sizeof(struct timeval)) == NULL) {
            syslog(LOG_ERR,
                    "Error: memset(): cannot fill struct timeval by zero");
            emerg_exit();
        }
        timeout.tv_sec = 10;
        timeout.tv_usec = 0;
        select_retval = select(readfd + 1, &rset, NULL, NULL, &timeout);
        if (select_retval == 0) { /* interrupted by timer */
            continue;
        }
        if (select_retval < 0) {
            if (errno == EINTR) {
                continue;
            }
            syslog(LOG_ERR,
                    "Error: select(): %s", strerror(errno));
            emerg_exit();
        }

        /* FD_ISSET(readfd, &rset) must be TRUE here */
        getchar_retval = pipe_getchar(readfd);
        if (getchar_retval == -1) {
            sleep(1);
            continue;
        }
        if (getchar_retval == -2) {
            emerg_exit();
        }

        cmd_str[cmd_pointer++] = (unsigned char) getchar_retval;

        /* we complete read the numeric value */
        if ((unsigned char) getchar_retval == '\0') {
            cmd_pointer = 0;

            if (run_osdcat(cmd_str)) {
                emerg_exit();
            }
        }
    } /* while (1) */

    return 0;
}

